home *** CD-ROM | disk | FTP | other *** search
- cseg segment para public 'code'
- org 100h
- userexit proc far
-
- ; The following equate should be set by the assembler.
- ; ps32 equ 0 ; 0 for 16-bit support, 1 for 32-bit support
-
- ; This program is an example of a memory-resident routine that is
- ; used to contain user breakpoints and user exits from Periscope.
- ; This program is attached to an unused interrupt vector so that it
- ; can be called from Periscope. The allowable range of vectors is
- ; 60H to FFH. This routine must be loaded into memory before Periscope
- ; is run. When PS.COM is run, be sure to specify the '/I:nn' installa-
- ; tion option, where nn is the interrupt vector.
-
- ; On entry, register AH contains a function number set by Periscope. For
- ; the user breakpoints, (BU 1 through 8), AH will be from 1 to 8. For
- ; the user exits (/U nn), AH will be from 9 to FFH. Note: F0 through FF
- ; are reserved for use by Periscope. The reserved functions are:
- ; F0 -- invoked after each command is entered, so that your code can
- ; modify the command line as needed.
- ; F1 -- invoked before a short boot (QS), so that your code can perform
- ; any required cleanup
- ; F2 -- invoked before a normal boot (QB)
- ; F3 -- invoked before a long boot (QL)
-
- ; On entry, DS:SI points to a table containing the current program's
- ; register values and other information. The information available is
- ; shown in the following structure:
-
- UserArgs struc
-
- if ps32 ; if 32-bit
-
- UserEAX dd ? ; the eax register
- UserEBX dd ? ; the ebx register
- UserECX dd ? ; the ecx register
- UserEDX dd ? ; the edx register
- UserESP dd ? ; the esp register
- UserEBP dd ? ; the ebp register
- UserESI dd ? ; the esi register
- UserEDI dd ? ; the edi register
- UserEIP dd ? ; the eip register
- UserDS dw ? ; the ds register
- UserES dw ? ; the es register
- UserSS dw ? ; the ss register
- UserCS dw ? ; the cs register
- UserFS dw ? ; the fs register
- UserGS dw ? ; the gs register
- UserEFL dd ? ; the eflags register
-
- ; extra registers
- UserGDT dw ? ; the gdt register (base & limit)
- dd ?
- UserIDT dw ? ; the idt register (base & limit)
- dd ?
- UserLDT dw ? ; the ldt register
- UserTR dw ? ; the tss register
- UserCR0 dd ? ; control reg 0
- UserCR1 dd ? ; control reg 1 - reserved
- UserCR2 dd ? ; control reg 2
- UserCR3 dd ? ; control reg 3
- UserDR0 dd ? ; debug reg 0
- UserDR1 dd ? ; debug reg 1
- UserDR2 dd ? ; debug reg 2
- UserDR3 dd ? ; debug reg 3
- UserDR4 dd ? ; debug reg 4 - reserved
- UserDR5 dd ? ; debug reg 5 - reserved
- UserDR6 dd ? ; debug reg 6
- UserDR7 dd ? ; debug reg 7
- ; the following test registers are available only when
- ; Periscope/Remote is used with a protect mode target system
- UserTR4 dd ? ; test reg 4 - 486 only
- UserTR5 dd ? ; test reg 5 - 486 only
- UserTR6 dd ? ; test reg 6
- UserTR7 dd ? ; test reg 7
-
- ErrorCode dd ? ; exception error code
-
- else ; if 16-bit
-
- UserAX dw ? ; the ax register
- UserBX dw ? ; the bx register
- UserCX dw ? ; the cx register
- UserDX dw ? ; the dx register
- UserSP dw ? ; the sp register
- UserBP dw ? ; the bp register
- UserSI dw ? ; the si register
- UserDI dw ? ; the di register
- UserDS dw ? ; the ds register
- UserES dw ? ; the es register
- UserSS dw ? ; the ss register
- UserCS dw ? ; the cs register
- UserIP dw ? ; the ip register
- UserFL dw ? ; the flags register
-
- endif
-
- UserSegment dw ? ; segment of address entered on user exit
- ; command line
-
- if ps32
- UserOffset dd ? ; offset of address entered on user exit
- else ; command line
- UserOffset dw ?
- endif
-
- UserBuffer dw 74/2 dup(?) ; current Periscope command, terminated with a
- ; carriage return and a nul
-
- UserPrevBuffer dw 74/2 dup(?) ; previous Periscope command, starting with a
- ; carriage return, and ending with a carriage
- ; return and a nul. Should not be modified!
- UserArgs ends
-
- ; On entry, ES:BX points to a user service routine in Periscope. This
- ; routine is accessed via a far call. Register AH is used to indicate
- ; the function desired. When using this routine, all registers are
- ; preserved. The functions available are:
- ;
- ; AH=1 -- display nul-terminated string at DS:SI. This function
- ; uses the standard Periscope display handler to display a string
- ; on the screen. The maximum length of the string is 83 characters,
- ; including a carriage return, line feed, and nul. The string must end
- ; with a nul (binary zero)!
- ;
- ; AH=2 -- get command string into UserBuffer. This function uses
- ; the standard Periscope keyboard handler to get an input string. The
- ; maximum length of the string is 74 characters, including a carriage
- ; return and a nul. Note that the new string is passed back at the
- ; same location as when the User Exit was first activated.
-
- ; AH=3 -- search symbol table for nul-terminated string passed in
- ; UserBuffer. This function returns the segment in UserSegment
- ; and the offset in UserOffset. If no symbol is found, the Carry flag
- ; is set.
-
- ; AH=4 -- search symbol table for symbol whose address is stored
- ; at UserSegment:UserOffset. The name is returned in UserBuffer. If no
- ; symbol is found, the Carry flag is set.
-
- ; AH=5 -- download and execute code on a Periscope remote driver.
- ; DS:SI points to a string whose length (0-64) is in the first byte.
- ; The following bytes are the code that is to be executed on the
- ; remote machine.
-
- ; AH=6 -- upload string from a Periscope remote driver. ES:DI points
- ; to a string whose length (0-64) is returned in the first byte.
- ; The following bytes are the data that is passed up from the remote
- ; system.
-
- ; AH=7 -- read a byte from a Periscope remote driver. ES:(E)DI points
- ; to the memory location to be read. The value is returned in AL.
-
- ; AH=8 -- write the byte in AL to a Periscope remote driver. ES:(E)DI
- ; points to the memory location to be written.
-
- ; On return from a USER BREAKPOINT, AL indicates whether or not the
- ; routine got a 'hit'. If AL=1, then Periscope assumes a hit and stops.
- ; Any other value is assumed not to be a hit and Periscope continues
- ; the GT command, unless another breakpoint (e.g. BW) is taken.
-
- ; On return from a USER EXIT, AL indicates whether the exit code has
- ; set a command to be executed by Periscope. If AL=2, Periscope reads
- ; the command line passed back from the user exit. The command line
- ; must start with a semi-colon and end with a carriage return.
-
- ; The values of registers other than AX, BX, SI, DS and ES on entry
- ; to the program are undefined.
-
- ; If your code will require more than 32 words of stack space, you
- ; should switch to your own internal stack. Be sure that Periscope's
- ; original stack is in place before returning to Periscope. All other
- ; registers may be modified as needed.
-
- assume cs:cseg,ds:cseg,ss:nothing,es:nothing
-
- start: jmp transient ; go to start-up code
-
- intno equ 60h ; use interrupt 60h
- cr equ 13 ; carriage return
- lf equ 10 ; line feed
-
- even
- pservice dd 0 ; periscope service routine's location
-
- signature db 'P','S' ; signature required by PS.COM - must be just
- ; before interrupt entry point!
-
- resident: ; interrupt entry point
- ; choose function based on value in ah
- push si
- mov si,offset pservice
- mov cs:[si],bx ; save service routine offset
- mov cs:[si+2],es ; save service routine segment
- pop si
-
- cld ; up periscope!
-
- cmp ah,1 ; ah=1?
- jz send1 ; yes - demo user breakpoint
-
- cmp ah,2 ; ah=2?
- jz send2 ; yes - test cs for range set by /u a
-
- cmp ah,9 ; ah=9?
- jz send9 ; yes - demo user exit
-
- cmp ah,0ah ; ah=a?
- jz senda ; yes - set cs range for use by 'bu 2'
-
- ife ps32
- cmp ah,0bh ; ah=b?
- jz sendb ; yes - display BASIC style string
-
- cmp ah,0ch ; ah=c?
- jz sendc ; yes - display BASIC PDS far string
- endif
-
- cmp ah,0eh ; ah=e?
- jz sende ; yes - another user exit
-
- cmp ah,52h ; ah=52h?
- jz send52 ; yes - execute code on remote ps
-
- cmp ah,53h ; ah=53h?
- jz send53 ; yes - read/write memory on remote ps
-
- cmp ah,87h ; ah=87h?
- jz send87 ; yes - display 8087/80287 status
-
- cmp ah,88h ; ah=88h?
- jz send88 ; yes - display dos memory allocation
-
- cmp ah,0f0h ; ah=f0 - ff?
- jae special
-
- exit: iret ; return to Periscope
-
- special:jz sendf0 ; yes - process command line
-
- cmp ah,0f1h ; ah=f1?
- jz sendf1 ; yes - intercept short boot
-
- cmp ah,0f2h ; ah=f2?
- jz sendf2 ; yes - intercept normal boot
-
- cmp ah,0f3h ; ah=f3?
- jz sendf3 ; yes - intercept long boot
-
- iret
-
- send1: jmp func1 ; jump table - inelegant, but fast
- send2: jmp func2
- send9: jmp func9
- senda: jmp funca
-
- ife ps32
- sendb: jmp funcb
- sendc: jmp funcc
- endif
-
- sende: jmp funce
- send52: jmp func52
- send53: jmp func53
- send87: jmp func87
- send88: jmp func88
- sendf0: jmp funcf0
- sendf1: jmp funcf1
- sendf2: jmp funcf2
- sendf3: jmp funcf3
-
-
- indos dd 0 ; pointer to in-dos flag
-
- func1: ; function 1
- ; This is an example of a user breakpoint to check for dos availability.
- ; It is invoked by specifying 'BU 1' and then using 'GT'.
-
- les di,cs:indos ; get pointer to in-dos flag
- cmp byte ptr es:[di],0 ; dos avail?
- jnz exit1 ; no
-
- if ps32
- test word ptr [si.UserEFL],0200h ; interrupts enabled?
- else
- test word ptr [si.UserFL],0200h ; interrupts enabled?
- endif
-
- jz exit1 ; no
-
- mov al,1 ; yes - it's a hit
-
- exit1: jmp exit
-
- lowcs dw 0 ; low value for cs test
- highcs dw 0 ; high value for cs test
-
- func2: ; function 2
- ; This is an example of a user *breakpoint* that checks the value of the
- ; CS register versus a range set by user *exit* '/u a'.
-
- mov bx,[si.UserCS] ; user's cs in bx
- cmp bx,cs:lowcs ; too low?
- jb exit2 ; yes
-
- cmp bx,cs:highcs ; too high?
- ja exit2 ; yes
-
- mov al,1 ; got one
-
- exit2: jmp exit
-
- commline db ';dd 0:0',cr ; ps command line - must start with a semi-colon
- ; and end with a carriage return
-
- commlen equ 8 ; length of command line
-
- func9: ; function 9
- ; This is an example of a user exit that stuffs a command into
- ; Periscope's command line.
-
- mov di,si
- add di,UserBuffer ; point to ps command line
- push ds
- pop es ; es:di point to ps command line
-
- push cs
- pop ds
- mov si,offset commline ; ds:si point to new command
-
- mov cx,commlen ; length must be <= 72 bytes!
- rep movsb ; copy command
-
- mov al,2 ; indicate that this is a command
-
- exit9: jmp exit
-
- funca: ; function a
- ; This user *exit* sets the range of the CS register for use by the
- ; user *breakpoint* 'bu 2'.
-
- mov ax,[si.UserSegment] ; get segment (low cs)
- mov cs:lowcs,ax
- mov ax,word ptr [si.UserOffset] ; get offset (high cs)
- mov cs:highcs,ax
-
- push cs
- pop ds ; ds=cs
-
- mov ax,lowcs ; get low cs value
- mov si,offset csval1
- call convert ; convert hex to ascii
-
- mov ax,highcs ; get high cs value
- mov si,offset csval2
- call convert ; convert hex to ascii
-
- mov si,offset csmsg
- mov ah,1 ; display message
- call [pservice] ; call service routine
-
- exita: jmp exit
-
- convert proc near ; convert hex number in ax to ascii at [si]
- push ax
- xchg ah,al
- call convertbyte ; convert lo byte
- pop ax
- ; convert hi byte
- convertbyte:
- push bx
- push cx
- mov ah,0
- mov bx,offset hextable
- mov cl,4
- shl ax,cl
- shr al,cl
- xlat
- xchg ah,al
- xlat
- mov [si],ax
- inc si
- inc si
- pop cx
- pop bx
- ret
- convert endp
-
- hextable db '0123456789ABCDEF' ; hex conversion table
- csmsg db 'CS range is from '
- csval1 db '.... to '
- csval2 db '....',cr,lf,0
-
- ife ps32
- funcb: ; function b
- ; This user exit displays a BASIC string for Quick Basic.
- ; It is called using '/ub <name>'
-
- mov cs:NearString,1 ; set "near string" flag
- jmp short CommonCode
-
- funcc: ; function c
- ; This user exit display a BASIC PDS far string.
- ; It is called using '/uc <name>'
-
- mov cs:NearString,0 ; reset the flag
-
- CommonCode: ; as in a cure for the common code?
- mov bx,[si.UserOffset] ; get symbol offset
- cmp bx,0 ; offset zero?
- jz funcb2 ; must not be a basic variable
-
- mov ds,[si.UserSegment] ; get symbol segment
- mov si,bx ; ds:si point to symbol
-
- cmp cs:NearString,1 ; processing a near string?
- jz DoNear
-
- ; Must be a far string
- mov ax,[si] ; Pointer to String length in string segment
- mov bx,[si+2] ; Pointer to string segment in (in DGROUP)
- mov ds,[bx] ; DS to string's segment
- xchg ax,bx
- mov bx,[bx] ; Pointer to string's length in bx
- mov cx,[bx] ; String's length into cx
- add bx,2 ; Add two bytes and that's the offset to the
- mov si,bx ; string. Put it in si.
- jmp short StringContinue
-
- DoNear:
- mov cx,[si] ; get length in cx
- mov si,[si+2] ; get offset in si
-
- StringContinue:
- push cs
- pop es ; es=cs
- mov di,offset outline
-
- push cx
- push di
- mov al,' '
- mov cx,80
- rep stosb ; clear outline
- pop di
- pop cx
-
- jcxz funcb2 ; zero length - exit
- cmp cx,80 ; 1-80?
- jbe funcb1 ; yes
-
- mov cx,80 ; limit it
-
- funcb1: rep movsb ; copy name to outline
-
- mov si,offset outline
-
- funcb3: mov ah,1
- push cs
- pop ds ; ds=cs
- call [pservice] ; display it
-
- exitb: jmp exit
-
- funcb2: mov si,offset nofind
- jmp funcb3
-
- nofind db 'Unknown symbol',cr,lf,0
- NearString db 0
- endif
-
- funce: ; function e (aka funky)
- ; This is an example of a user exit that gets a symbol name and
- ; then attempts to search the symbol table. If the symbol search
- ; by name is successful, the symbol table is searched by address.
-
- push cs
- pop ds
-
- mov si,offset prompt
- mov ah,1 ; display message
- call [pservice] ; call service routine
-
- mov ah,2 ; get input string
- call [pservice] ; call service routine
-
- mov ah,3 ; search symbol table by name
- call [pservice] ; call service routine
- jnc funce1 ; found it
-
- mov si,offset nofind1
- mov ah,1 ; display message
- call [pservice] ; call service routine
- jmp exite ; quit
-
- funce1: mov si,offset find1
- mov ah,1 ; display message
- call [pservice] ; call service routine
-
- mov ah,4 ; search symbol table by address
- call [pservice] ; call service routine
- jnc funce2 ; found it
-
- mov si,offset nofind2
- jmp funce3
-
- funce2: mov si,offset find2
-
- funce3: mov ah,1 ; display message
- call [pservice] ; call service routine
-
- exite: jmp exit
-
- prompt db 'Symbol name? ',0
- nofind1 db 'Symbol not found by name',cr,lf,0
- find1 db 'Symbol found by name',cr,lf,0
- nofind2 db 'Symbol not found by address',cr,lf,0
- find2 db 'Symbol found by address',cr,lf,0
-
- func52: ; function 52
- ; This is an example of a user exit that downloads some code to
- ; a periscope remote driver and then runs that code. The routine
- ; then reads the results of the code that was run.
-
- mov ax,cs
- mov ds,ax
- mov si,offset codesample; ds:si point to code string to be passed
-
- mov ah,5 ; download code
- call [pservice] ; call service routine
-
- mov ax,cs
- mov es,ax
- mov di,offset uplen
-
- mov ah,6 ; upload string from remote
- call [pservice] ; call service routine
- cmp uplen,1 ; got 1 byte?
- jnz exit52 ; no - error
-
- mov al,upstring ; use first byte only
- mov si,offset portval
- call convertbyte ; convert hex to ascii
-
- mov ah,1
- mov si,offset portmsg
- call [pservice] ; display result
-
- exit52: jmp exit
-
- ife ps32
-
- codesample proc near ; this is for a real mode remote system
- db offset endcode-$ ; length of code
- mov al,1
- stosb ; output 1 byte
- in al,21h ; get value of port 21h
- stosb ; return byte in al
- ret ; must be a near return!
- endcode equ $-1
- codesample endp
-
- else
-
- codesample proc near ; this is for a protected mode remote system
- ; The following is not for the faint of heart. Since the code will
- ; be running on a 32-bit protect mode system, you'll need to generate
- ; full 32-bit code. One way to do it is to patch in any differences.
-
- db offset endcode-$ ; length of code
- mov al,1
- stosb ; output 1 byte
- in al,21h ; get value of port 21h
- stosb ; return byte in al
- retf ; must be a far dword return!
- endcode equ $-1
- codesample endp
-
- endif
-
- uplen db 0
- upstring db 0,0
- dw 31 dup(0) ; keep this after uplen
-
- portmsg db 'The value read from port 21h on the remote system is '
- portval db '??H.',cr,lf,0
-
- func53: ; function 53
- ; This is an example of a user exit that reads memory on
- ; a periscope remote driver.
-
- mov ax,cs
- mov ds,ax
-
- xor di,di
- mov es,di ; point to 0:0 (int 0)
-
- mov ah,7 ; read memory
- call [pservice] ; call service routine
-
- mov si,offset readvalue
- call convertbyte ; convert hex to ascii
-
- mov ah,1
- mov si,offset readmsg
- call [pservice] ; display result
-
- exit53: jmp exit
-
- readmsg db 'The value at 0:0 is '
- readvalue db '??H.',cr,lf,0
-
- func87: ; function 87 - display 8087/80287 status
- push cs
- pop ds ; ds=cs
-
- push ds
- pop es ; es=ds
- call p330 ; clear output line
-
- cmp ndpfound,1 ; ndp found at start time?
- jnz no87 ; no
-
- fstenv ndpctrl ; save ndp environment
- fldenv ndpctrl ; restore it
-
- call p200 ; display control info
- call p210 ; display status line
- call p220 ; display ip, opcode, and dp
- call p230 ; display tag words
-
- exit87: jmp exit
-
- no87: mov ah,1
- mov si,offset no87msg
- call [pservice] ; display line
- jmp exit87
-
- func88: ; function 88 - display dos memory allocation
-
- push cs
- pop ds ; ds=cs
- cmp dosver,2 ; dos 2.x?
- jz exit88 ; yes - exit
-
- xor di,di
- mov priorseg,di
- mov pspseg,di
- mov ax,dosmemseg ; get start seg for dos memory alloc blocks
- mov lastseg,ax
- call p110 ; get segment for dos
- jc exit88 ; error
-
- mov dx,es
- inc dx
- mov pspseg,dx
- mov si,offset command
- mov di,offset outline+6
- push cs
- pop es ; es=cs
- mov cx,14
- rep movsb ; copy command over
- jmp p104 ; continue
-
- exit88: jmp exit
-
- p101: push cs
- pop ds ; ds=cs
- xor di,di
- mov es,priorseg
- cmp byte ptr es:[di],5ah ; end?
- jz exit88 ; yes
-
- call p110 ; get segment
- jc exit88 ; error
-
- mov dx,es
- inc dx
- mov pspseg,dx
- mov ds,dx ; ds=prior es
- mov si,2ch
- lodsw ; get environment
- cmp ax,0 ; nul?
- jz exit88 ; yes - exit
-
- mov ds,ax
- xor si,si
-
- p102: lodsb ; search for nul
- cmp al,0
- jnz p102
-
- lodsb ; got one - look for second
- cmp al,0
- jnz p102
-
- lodsw ; look for 1,0
-
- mov cx,80 ; max length
- mov di,offset outline
- push cs
- pop es ; es=cs
-
- mov al,' '
- push cx
- rep stosb ; clear output area
- pop cx
- mov di,offset outline+6
-
- p103: lodsb ; get char
- cmp al,0 ; end?
- jz p104 ; yes
-
- stosb ; save char
- loop p103 ; continue
-
- p104: push cs
- pop ds ; get orig ds back
-
- mov ax,pspseg
- mov si,offset outline
- call convert ; convert psp
-
- mov ah,1
- mov si,offset outline
- call [pservice] ; display line
- jmp p101
-
- p110 proc near
- mov ax,lastseg
- xor di,di ; be sure
-
- p111: mov es,ax ; get segment
- add ax,es:[di+3] ; add next segment into ax
- inc ax ; plus one
- mov bx,es:[di+1] ; get psp seg
- mov cx,es ; get current segment
- cmp byte ptr es:[di],4dh; mem alloc block?
- jz p112 ; yes
-
- cmp byte ptr es:[di],5ah ; end of chain?
- jnz p113 ; no - error
-
- p112: inc cx ; current segment plus one
- cmp bx,cx ; psp seg?
- jnz p111 ; no - keep on
-
- mov lastseg,ax
- mov priorseg,es
- clc
- ret
-
- p113: stc
- ret
- p110 endp
-
- dosver db 0
- dosmemseg dw 0
- lastseg dw 0
- priorseg dw 0
- pspseg dw 0
- command db 'COMMAND.COM',cr,lf,0
-
- funcf0: ; function f0
- ; This is an example of a reserved user exit. If a user exit is
- ; installed, function F0H is activated after each command is entered,
- ; but before it is processed by Periscope. At this time, the user exit
- ; can modify the command as desired, using the command area defined
- ; above. No registers need to be set -- just modify the command line
- ; as desired.
-
- add si,20h ; point to ps command line
- mov ax,[si] ; get first word
- cmp ax,'..' ; double dot?
- jnz exitf0 ; no
-
- mov word ptr [si],'dd' ; yes - convert it to dd
-
- exitf0: jmp exit
-
- funcf1: ; function f1
- ; This is an example of a reserved user exit. If a user exit is
- ; installed, function F1H is activated before a short boot.
-
- call beep ; beep once
- jmp exit
-
- funcf2: ; function f2
- ; This is an example of a reserved user exit. If a user exit is
- ; installed, function F2H is activated before a normal boot.
-
- call beep ; beep twice
- call beep
- jmp exit
-
- funcf3: ; function f3
- ; This is an example of a reserved user exit. If a user exit is
- ; installed, function F3H is activated before a long boot.
-
- call beep ; beep three times
- call beep
- call beep
- jmp exit
-
- beep proc near
- push ax
- push bx
- push cx
- push es
- pushf
- sti
-
- xor ax,ax
- mov es,ax
- mov bx,46ch ; offset of low timer word
-
- mov al,0b6h
- out 43h,al ; set timer
- mov al,33h
- out 42h,al
- jmp $+2 ; wait
-
- mov al,3
- out 42h,al
- in al,61h
- mov ah,al ; save orig value
- or al,3
- jmp $+2 ; wait
-
- call beepa ; sync it
-
- out 61h,al ; speaker on
- call beepa ; wait 1
-
- mov al,33h
- out 42h,al
- jmp $+2
-
- mov al,6
- out 42h,al
- call beepa ; wait 1
-
- mov al,ah
- out 61h,al ; back to initial value
-
- popf
- pop es
- pop cx
- pop bx
- pop ax
- ret
-
- beepa: mov cx,es:[bx] ; get timer value
-
- beepb: jmp $+2
- cmp cx,es:[bx] ; same?
- jz beepb ; yes - wait
-
- ret
- beep endp
-
- ; control word equates
- nbic equ 1000h ; ic - bit 12
- nbrc equ 0c00h ; rc - bits 10,11
- nbpc equ 0300h ; pc - bits 8,9
- nbpm equ 0020h ; pm - bit 5
- nbum equ 0010h ; um - bit 4
- nbom equ 0008h ; om - bit 3
- nbzm equ 0004h ; zm - bit 2
- nbdm equ 0002h ; dm - bit 1
- nbim equ 0001h ; im - bit 0
-
- ; status word equates
- nbby equ 8000h ; busy
- nbc3 equ 4000h ; cond code 3
- nbtop equ 3800h ; top of stack
- nbc2 equ 0400h ; cond code 2
- nbc1 equ 0200h ; cond code 1
- nbc0 equ 0100h ; cond code 0
- nbes equ 0080h ; err status
-
- ; control word text
- ndpc1 db 'Ctrl: Infin=',0
- ndpc2 db ' Round=',0
- ndpc3 db ' Prec=',0
- ndpc4 db ' Flags=',0
-
- ; status word text
- ndps1 db 'Stat: Cond=',0
- ndps2 db ' Stacktop=',0
-
- ; misc text
- ndpip db 'IP=',0
- ndpop db 'Opcode=',0
- ndpdp db 'DP=',0
- ndptag db 'Tag: ',0
- ndpflags db 'PrecUndrOverZeroDen Inv ' ; possible flags
- ndpbusy db 'Busy'
- ndperr db 'Err '
- ndpinf0 db 'Proj'
- ndpinf1 db 'Aff '
- ndprnd db 'NearDownUp Chop' ; round types
- ndpprec db 'Short?????Long Temp ' ; precision types
- ndptval db 'ValidZero InfinEmpty' ; tag values
-
- ; ndp save area
- ndpctrl dw 0 ; save area - control word
- ndpstat dw 0 ; status word
- ndptagw dw 0 ; tag word
- ndpip1 dw 0 ; inst ptr 1
- ndpip2 dw 0 ; inst ptr 2
- ndpdp1 dw 0 ; data ptr 1
- ndpdp2 dw 0 ; data ptr 2
-
- no87msg db 'No numeric processor found',cr,lf,0
- ndpfound db 0 ; 1 if ndp found
- ndpstate dw 0 ; startup test word
-
- outline db ' ',' '
- dw 39 dup(' ') ; output work line
- db cr,lf,0
-
- p200 proc near ; display control info
- mov ax,ndpctrl
- mov si,offset ndpc1
- call p300 ; copy control header
- mov si,offset ndpinf0 ; assume projective
- test ax,nbic ; proj?
- jz p201 ; yes
-
- mov si,offset ndpinf1 ; no
-
- p201: movsw ; copy infinity type
- movsw
-
- mov si,offset ndpc2
- call p300 ; copy round header
- mov si,offset ndprnd ; assume near
-
- mov bx,ax ; get word in bx
- and bx,nbrc ; clear other bits
- xchg bh,bl ; times four as is
- add si,bx
- movsw ; copy round type
- movsw
-
- mov si,offset ndpc3
- call p300 ; copy precision header
- mov si,offset ndpprec
- mov bx,ax
- and bx,nbpc
- xchg bh,bl
- mov cx,bx
- shl bx,1 ; times 2
- shl bx,1 ; times 4
- add bx,cx ; times 5
- add si,bx
- movsw ; copy precision type
- movsw
- movsb
-
- call p320 ; display flags
- call p340 ; print line
- ret
- p200 endp
-
- p210 proc near ; display status info
- mov ax,ndpstat
- mov si,offset ndps1
- call p300 ; copy status header
- test ax,nbc3 ; cc3 on?
- call p310 ; print result
- test ax,nbc2 ; cc2 on?
- call p310
- test ax,nbc1
- call p310
- test ax,nbc0
- call p310
-
- mov si,offset ndps2
- call p300 ; copy stacktop header
- mov bx,ax
- and bx,nbtop
- shr bx,1
- shr bx,1
- shr bx,1 ; in bh
- add bh,'0' ; make ascii
- mov [di],bh
- inc di
- inc di
- inc di
-
- test ax,nbby ; busy?
- jnz p211 ; yes
-
- add di,4 ; no
- jmp short p212
-
- p211: mov si,offset ndpbusy
- movsw
- movsw
-
- p212: inc di
- inc di
-
- test ax,nbes ; error?
- jnz p213 ; yes
-
- inc di
- inc di
- inc di
- jmp short p214
-
- p213: mov si,offset ndperr
- movsw
- movsb
-
- p214: inc di
- call p320 ; display flags
- call p340 ; display line
- ret
- p210 endp
-
- p220 proc near ; display ip, opcode, and dp
- mov si,offset ndpip
- call p300 ; copy ip header
- mov ax,ndpip2 ; get ip
- mov cx,4
- rol ax,cl ; address in low 4 bits
- call p350 ; display nibble
- mov ax,ndpip1 ; get lower part of ip
- call p360 ; display word
-
- mov si,offset ndpop
- call p300 ; copy opcode header
- mov ax,ndpip2
- and ax,07ffh ; clear out ip part
- or ax,0d800h ; make it an esc instruction
- call p360 ; display word
-
- mov si,offset ndpdp
- call p300 ; copy dp header
- mov ax,ndpdp2 ; get dp
- mov cx,4
- rol ax,cl ; address in low 4 bits
- call p350 ; display nibble
- mov ax,ndpdp1 ; get lower part of dp
- call p360 ; display word
-
- call p340 ; display line
- ret
- p220 endp
-
- p230 proc near ; display tag word
- mov si,offset ndptag
- call p300 ; copy tag header
- mov ax,ndptagw ; get tag word
- mov cx,8
-
- p231: rol ax,1
- rol ax,1 ; get next tag word
- push ax
- and ax,3
- mov bx,ax
- shl ax,1
- shl ax,1
- add bx,ax ; times five
- mov si,offset ndptval ; point to tag values
- add si,bx
- movsw
- movsw
- movsb ; copy to output
- inc di
- inc di ; two spaces
- pop ax
- loop p231
-
- call p340 ; display line
- ret
- p230 endp
-
- p300 proc near ; copy to output line
- push ax
-
- p301: lodsb ; get byte
- cmp al,0 ; end?
- jz p305 ; yes
-
- stosb ; no - save it
- jmp p301 ; continue
-
- p305: pop ax
- ret
- p300 endp
-
- p310 proc near ; print 0 if zr, else 1
- mov bl,'0'
- jz p315
-
- mov bl,'1'
-
- p315: mov [di],bl
- inc di
- ret
- p310 endp
-
- p320 proc near ; display flags
- mov si,offset ndpc4
- call p300 ; copy flags header
- mov si,offset ndpflags
- mov bx,nbpm ; start w/ pm
- mov cx,6 ; six flags
-
- p321: test ax,bx ; bit on?
- jnz p322 ; yes
-
- add si,4 ; next name
- add di,4
- jmp short p323
-
- p322: movsw ; yes - copy it
- movsw
-
- p323: inc di ; skip one
- shr bx,1 ; next test
- loop p321
- ret
-
- p320 endp
-
- p330 proc near ; clear output line
- mov di,offset outline
- push di
- mov cx,80/2 ; length
- mov ax,' ' ; spaces
- rep stosw ; init to spaces
- pop di
- ret
- p330 endp
-
- p340 proc near ; print output line
- mov ah,1 ; use periscope display
- mov si,offset outline ; ds:si point to string
- call [pservice] ; call periscope service routine
- call p330
- ret
- p340 endp
-
- p350 proc near ; display nibble
- push ax
- and ax,0fh
- cmp ax,9 ; 0 to 9?
- ja p351 ; no - a to f
-
- add ax,'0' ; convert to ascii
- jmp short p352
-
- p351: add ax,55 ; a - f
-
- p352: stosb ; save byte
- pop ax
- ret
- p350 endp
-
- p360 proc near ; display word
- mov bx,4 ; counter
-
- p361: rol ax,cl ; move to low nibble
- call p350 ; display it
- dec bx
- jnz p361 ; not done
-
- inc di
- inc di ; two spaces
- ret
- p360 endp
-
- transient: ; end of resident code and
- ; start of transient code
-
- cld ; up periscope!
-
- ; test for numeric processor
- fninit ; initialize it - no wait
- mov cx,20
- loop $ ; wait around for command to take
-
- mov bx,offset ndpstate
- fnstcw [bx] ; store control word - no wait
- mov cx,20
- loop $ ; wait around
-
- mov ax,[bx] ; get value
- and ax,0f3fh
- cmp ax,033fh ; ndp found?
- jnz trans2 ; no
-
- mov ndpfound,1 ; yes
-
- trans2: ; init variables for function 88
- mov ah,30h
- int 21h ; get DOS version
- mov dosver,al
-
- push es
- mov ah,52h
- mov bx,cs
- int 21h ; get dos memory block pointer
- mov ax,es:[bx-2]
- mov dosmemseg,ax
- pop es
-
- mov ah,34h ; set in-dos pointer
- int 21h
- mov si,offset indos
- mov [si],bx ; save offset
- mov [si+2],es ; and segment for user breakpoint 1
-
- xor ax,ax
- mov es,ax
- mov di,intno ; get int number
- shl di,1
- shl di,1 ; times 4
-
- cli ; no interrupts
- mov ax,offset resident ; point interrupt to resident code
- stosw ; set offset
- mov ax,ds
- stosw ; and segment
- sti ; interrupts back on
-
- mov dx,offset transient
- int 27h ; stay resident
-
- userexit endp
- cseg ends
- end userexit